from common import *

class Token:
	def __init__(self, value_type, value):
		self.value_type = value_type
		self.value = value

	def __str__(self):
		return 'Token({value_type},{value})'.format(value_type=self.value_type, value=self.value)

	def viewTree(self):
		# return {'Token':{'value_type':self.value_type,'value':self.value}}
		return {'value_type':self.value_type,'value':self.value}

# 保留字字典
RESERVED_KEYWORDS = {
	'PROGRAM': Token('PROGRAM', 'PROGRAM'),
	'VAR': Token('VAR', 'VAR'),
	'DIV': Token('INTEGER_DIV', 'DIV'),
	'INTEGER': Token('INTEGER', 'INTEGER'),
	'REAL': Token('REAL', 'REAL'),
	'BEGIN': Token(BEGIN, 'BEGIN'),
	'END': Token(END, 'END')
}

class Lexer:
	def __init__(self, text):
		self.text = text
		self.position = 0
		self.current_char = self.text[self.position]

	def error(self):
		raise Exception('警告：错误的输入内容！')

	def skip_whitespace(self):
		while self.current_char is not None and self.current_char.isspace():
			self.advance()

	def long_integer(self):
		result = ''
		while self.current_char is not None and self.current_char.isdigit():
			result += self.current_char
			self.advance()
		return int(result)

	def advance(self):
		self.position += 1
		if self.position >= len(self.text):
			self.current_char = None
		else:
			self.current_char = self.text[self.position]



	'''
		查看下一字符的方法。
		为了区别开头相同的不同记号（例如“:”和“:=”），我们需要在遇到特定开头的记号时查看下一字符，并且不能让位置增加。
	'''
	def peek(self):
		# 获取下一个位置
		pos=self.position+1
		# 如果超出文本末端
		if pos>=len(self.text):
			return None  # 返回None
		else:
			return self.text[pos] # 返回下一位置字符
	# 获取保留字或赋值名称记号的方法
	def _id(self):
		result = ''
		# 如果当前字符是字母数字
		while self.current_char is not None and self.current_char.isalnum():
			result += self.current_char  # 连接字符
			self.advance()  # 提取下一个字符
		# 如果是保留字返回保留字记号，默认返回ID记号
		token = RESERVED_KEYWORDS.get(result, Token('ID', result))
		return token


	# 添加跳过注释内容到的方法
	def skip_comment(self):
		while self.current_char != '}':  # 如果当前字符不是注释结束符号
			self.advance()  # 提取下一个字符
		self.advance()  # 提取下一个字符（跳过注释结束符号）
	# 添加跳过斜杠注释内容到的方法
	def skip_slash_comment(self):
		while self.current_char != '\n':  # 如果当前字符不是注释结束符号
			self.advance()  # 提取下一个字符
		self.advance()  # 提取下一个字符（跳过注释结束符号）
	# 添加跳过多行注释内容到的方法
	def skip_multiline_comment(self):
		while self.current_char != '*' and self.peek() != '/':  # 如果当前字符不是注释结束符号
			self.advance()  # 提取下一个字符
		self.advance()  # 提取下一个字符（跳过注释结束符号）
	# 添加处理整数和实数的方法
	def number(self):
		result = ''  # 定义保存数字字符串的变量
		while self.current_char is not None and self.current_char.isdigit():  # 如果当前字符不是None并且为整数
			result += self.current_char  # 连接已有数字字符串
			self.advance()  # 提取下一字符
			if self.current_char == '.':  # 如果当前字符为小数点
				result += self.current_char  # 连接已有数字字符串
				self.advance()  # 提取下一字符
				while self.current_char is not None and self.current_char.isdigit():  # 如果当前字符不是None并且为整数（小数点后均为整数）
					result += self.current_char  # 连接已有数字字符串
					self.advance()  # 提取下一字符
				return Token(REAL_CONST, float(result))  # 遍历完小数点右侧所有整数后，返回存储了小数数值的实数记号。
		return Token(INTEGER_CONST, int(result))  # 没有小数点时，遍历完所有整数后，返回存储了整数数值的整数记号。



	def get_next_token(self):
		while self.current_char is not None:
			if self.current_char == '{':  # 如果当前字符为注释起始标记
				self.advance()  # 跳过当前字符
				self.skip_comment()  # 跳过注释内容
				continue  # 继续获取下一记号
			if self.current_char == '/' and self.peek() == '/':  # 如果当前字符为斜杠注释起始标记
				self.advance()  # 跳过当前字符
				self.skip_slash_comment()  # 跳过斜杠注释内容
				continue  # 继续获取下一记号
			if self.current_char == '/' and self.peek() == '*':  # 如果当前字符为多行注释起始标记
				self.advance()  # 跳过当前字符
				self.advance()  # 跳过当前字符
				self.skip_multiline_comment()  # 跳过多行注释内容
				continue  # 继续获取下一记号
			if self.current_char.isspace():
				self.skip_whitespace()
				continue
			if self.current_char.isalpha() or self.current_char == '_':  # 如果当前字符是字母或下划线（支持变量名称下划线开头）
				return self._id()
			if self.current_char == ':' and self.peek() == '=':
				self.advance()
				self.advance()
				return Token(ASSIGN, ':=')
			if self.current_char == ';':
				self.advance()
				return Token(SEMI, ';')
			if self.current_char == '.':
				self.advance()
				return Token(DOT, '.')
			if self.current_char.isdigit():  # 当前字符为整数时
				return self.number()  # 获取整数或实数记号
			if self.current_char == ':':  # 当前字符为冒号时
				self.advance()  # 提取下一字符
				return Token(COLON, ':')  # 返回冒号记号
			if self.current_char == ',':  # 当前字符为逗号时
				self.advance()  # 提取下一字符
				return Token(COMMA, ',')  # 返回逗号标记
			if self.current_char == '+':
				self.advance()
				return Token(PLUS, '+')
			if self.current_char == '-':
				self.advance()
				return Token(MINUS, '-')
			if self.current_char == '*':
				self.advance()
				return Token(MUL, '*')
			if self.current_char == '/':  # 当前字符为斜杠时
				self.advance()  # 提取下一字符
				return Token(FLOAT_DIV, '/')  # 返回浮点数除法记号
			if self.current_char == '(':
				self.advance()
				return Token(LPAREN, '(')
			if self.current_char == ')':
				self.advance()
				return Token(RPAREN, ')')
			self.error()
		return Token(EOF, None)




